package com.roamer.service;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.roamer.config.JuHeWeatherProperties;
import com.roamer.vo.WeatherRestResult;
import com.roamer.vo.WeatherVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 聚合天气查询服务
 *
 * @author roamer
 * @version v1.0
 * @date 2020/3/26 13:15
 */
@Slf4j
@Service
class JuHeWeatherService {


    private final JuHeWeatherProperties properties;

    private final RestTemplate restTemplate;

    private volatile Cache<String, WeatherVO> cache = null;

    private static ObjectMapper mapper = new ObjectMapper();

    static {
        // 转换为格式化的json
        mapper.enable(SerializationFeature.INDENT_OUTPUT);
        // 如果json中有新增的字段并且是实体类类中不存在的，不报错
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    }

    public JuHeWeatherService(JuHeWeatherProperties properties, RestTemplate restTemplate) {
        this.properties = properties;
        this.restTemplate = restTemplate;
    }

    WeatherVO getCityWeather(String city) {
        initCache();
        try {
            WeatherVO weatherVO = cache.getIfPresent(city);
            if (weatherVO == null) {
                weatherVO = doGet(city);
                // 放入缓存
                if (weatherVO != null) {
                    cache.put(city, weatherVO);
                }
            }
            return weatherVO;
        } catch (Exception e) {
            throw new RuntimeException("[聚合API查询天气] 查询异常", e);
        }
    }

    private WeatherVO doGet(String city) throws JsonProcessingException {
        log.info("[聚合API查询天气] -> 城市:[{}]", city);
        // api查询
        ResponseEntity<WeatherRestResult> responseEntity = restTemplate.exchange(
                properties.getUrl().concat("?city={city}&key={key}"),
                HttpMethod.GET,
                null,
                new ParameterizedTypeReference<WeatherRestResult>() {
                },
                city, properties.getKey());
        WeatherRestResult restResult;
        WeatherRestResult.ResultInfo resultInfo;
        log.info("[聚合API查询天气] -> 结果:[{}]", mapper.writeValueAsString(responseEntity));
        // 查询成功
        if (HttpStatus.OK.equals(responseEntity.getStatusCode()) &&
                (restResult = responseEntity.getBody()) != null &&
                0 == restResult.getError_code() &&
                (resultInfo = restResult.getResult()) != null) {
            WeatherRestResult.Realtime realtime = resultInfo.getRealtime();
            List<WeatherRestResult.Future> futures = resultInfo.getFuture();
            WeatherVO weather = new WeatherVO();
            weather.setCity(resultInfo.getCity());
            weather.setTemperature(realtime.getTemperature());
            // 最高温度/最低温度
            if (futures != null && futures.size() > 0) {
                String temperature = futures.get(0).getTemperature();
                int index;
                if ((index = temperature.lastIndexOf("℃")) > 0) {
                    temperature = temperature.substring(0, index);
                }
                String[] split = temperature.split("\\/");
                if (split.length == 2) {
                    weather.setMinTemperature(split[0]);
                    weather.setMaxTemperature(split[1]);
                }

            }
            weather.setWeather(realtime.getInfo());
            weather.setCreateDate(new Date());
            // 新查询的标记
            weather.setNewFlag(true);
            return weather;
        }
        log.warn("[聚合API查询天气失败] -> 原因:[{}]", mapper.writeValueAsString(responseEntity));
        return null;
    }

    private void initCache() {
        if (cache == null) {
            synchronized (this) {
                if (cache == null) {
                    cache = CacheBuilder.newBuilder()
                            .expireAfterWrite(properties.getTimeoutOfMinute(), TimeUnit.MINUTES)
                            .build();
                }
            }
        }
    }

}
